
#include "comLogManager.h"
#include "ProjectDocMgr.h"

#include "ttcodeStateChart.h"

#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

#include "tinyxml/tinyxml.h"


std::string UUIDGen()
{
 	boost::uuids::random_generator gen;
	boost::uuids::uuid u = gen();
	std::stringstream ss;
	ss << u;
	return ss.str();
}


ProjectDocMgr::ProjectDocMgr()
:m_ProjectFileName("")
,m_Xml(NULL)
,m_ModifyFlag(false)
{
}
ProjectDocMgr::~ProjectDocMgr()
{
	if( NULL != m_Xml && m_ModifyFlag )
	{
		m_Xml->SaveFile();
		ttcode_log << endl;
		delete m_Xml;
	}
}

void ProjectDocMgr::loadProjectFile( const string & docPath )
{
	ttcode_log << "docPath=" << docPath << endl;
	if( NULL != m_Xml && m_ModifyFlag )
	{
		m_Xml->SaveFile();
		m_ModifyFlag = false;
		delete m_Xml;
	}
	m_ProjectFileName = docPath;
	try
	{
		m_Xml = new TiXmlDocument(docPath);
		m_Xml->LoadFile();
		ttcode_log << "m_Xml=" << m_Xml << endl;
		m_Root = m_Xml->RootElement();
		ttcode_log << "m_Root=" << m_Root << endl;
	}
	catch(std::exception e)
	{
		ttcode_log << "exception:" << e.what() << endl;
		m_ProjectFileName = "";
	}
	if( !m_ProjectFileName.empty() )
	{
		boost::filesystem::path doc_path(m_ProjectFileName);
		globalTTEnv["doc_home"] = doc_path.parent_path().string();
	}
	this->checkIntegration( m_Root );
	if( m_ModifyFlag )
	{
		m_Xml->SaveFile();
		m_ModifyFlag = false;
	}
}

void ProjectDocMgr::checkIntegration( TiXmlElement* elem )
{
	if( NULL == elem )
	{
		return;
	}
	const char *value = elem->Value();
	if( NULL == value )
	{
		return;
	}
	string sValue(value);
	if( "file" == sValue )
	{
		const char * pLang = elem->Attribute("lang");
		if( NULL == pLang )
		{
			this->fixFileLang(elem);
		}
	}
	else if ( "target" == sValue )
	{
		const char * pLang = elem->Attribute("lang");
		if( NULL == pLang )
		{
			this->fixTargetLang( elem );
		}
		this->tryFixTargetOutDir( elem );
	}
	else
	{}
	// do check all children
	TiXmlElement* sub = elem->FirstChildElement();
	for( ; sub ; sub = sub->NextSiblingElement() )
	{
		this->checkIntegration(sub);
	}
}

void ProjectDocMgr::fixFileLang( TiXmlElement* elem )
{
	const char * pPath = elem->Attribute("path");
	if( NULL == pPath )
	{
		return;
	}
	boost::filesystem::path fsPath(pPath);
	string strLang = boost::filesystem::extension(fsPath);
	boost::to_lower(strLang);
	string type = globalFileType[strLang];
	if( "head" == type )
	{
		elem->SetAttribute("lang","H");
	}
	else if( "cstd" == type )
	{
		elem->SetAttribute("lang","C");
	}
	else if( "cpp" == type )
	{
		elem->SetAttribute("lang","CXX");
	}
	else if( "cl" == type )
	{
		elem->SetAttribute("lang","CL");
	}
	else
	{
		elem->SetAttribute("lang","unkonw");
	}
	m_ModifyFlag = true;
}

void ProjectDocMgr::fixTargetLang( TiXmlElement* elem )
{
	bool c = false;
	bool cxx = false;
	// do check all "compile_file"
	TiXmlElement* compile = elem->FirstChildElement("compile_file");
	for( ; compile ; compile = compile->NextSiblingElement("compile_file") )
	{
		TiXmlElement* source = compile->FirstChildElement("source_item");
		for( ; source ; source = source->NextSiblingElement("source_item") )
		{
			const char *pId = source->GetText();
			if( NULL == pId)
			{
				continue;
			}
			TiXmlElement* file = this->getElementById(string(pId));
			if( NULL == file)
			{
				continue;
			}
			const char *pLang = file->Attribute("lang");
			if( NULL == pLang)
			{
				continue;
			}
			string sLang(pLang);
			if( "C" == sLang)
			{
				c = true;
			}
			else if( "CXX" == sLang)
			{
				cxx = true;
			}
			else
			{}

		}
	}
	if(cxx)
	{
		elem->SetAttribute("lang","CXX");
	}
	else if(c)
	{
		elem->SetAttribute("lang","C");
	}
	else
	{
		elem->SetAttribute("lang","unkonw");
	}
	m_ModifyFlag = true;
}

void ProjectDocMgr::tryFixTargetOutDir( TiXmlElement* elem )
{
	// do check all "outdir"
	bool modify = false;
	TiXmlElement* outdir = elem->FirstChildElement("outdir");
	if( NULL == outdir )
	{
		outdir = new TiXmlElement("outdir");
		outdir->SetAttribute("id",UUIDGen());
		outdir->SetAttribute("fix","false");
		elem->LinkEndChild(outdir);
		m_ModifyFlag = true;
		modify = true;
	}
	else
	{
//		const char* pFix = outdir->Attribute("fix");
//		if(pFix && "false" == string(pFix))
//		{
//			outdir->Clear();
//			m_ModifyFlag = true;
//		}
	}
	if(modify)
	{
		string sOutDir = globalTTEnv["doc_home"] + "/build";
		TiXmlText *ctext = new TiXmlText(sOutDir);
		outdir->LinkEndChild(ctext);
	}
}







TiXmlElement* ProjectDocMgr::getElement( const string & name )
{
	TiXmlElement* ret = searchElementByName(m_Root,name);
	return ret;
}

TiXmlElement* ProjectDocMgr::searchElementByName(TiXmlElement* root,const string & name)
{
	if( NULL == root )
	{
		return NULL;
	}
//	ttcode_log << "root=" << root << endl;
	const char *value = root->Value();
	if( value && name == string(value) )
	{
		return root;
	}
	TiXmlElement* item = root->FirstChildElement();
	for( ; item ; item = item->NextSiblingElement() )
	{
		TiXmlElement* ret = searchElementByName(item,name);
		if( ret )
		{
			return ret;
		}
	}
	return NULL;
}
TiXmlElement* ProjectDocMgr::getElementById( const string & id )
{
	TiXmlElement* ret = searchElementById(m_Root,id);
	return ret;
}

TiXmlElement* ProjectDocMgr::searchElementById(TiXmlElement* root,const string & id)
{
	if( NULL == root )
	{
		return NULL;
	}
//	ttcode_log << "root=" << root << endl;
	const char *value = root->Attribute("id");
	if( value && id == string(value) )
	{
		return root;
	}
	TiXmlElement* item = root->FirstChildElement();
	for( ; item ; item = item->NextSiblingElement() )
	{
		TiXmlElement* ret = searchElementById(item,id);
		if( ret )
		{
			return ret;
		}
	}
	return NULL;
}



void ProjectDocMgr::modifyLogInfo( const string & id ,const string & name,const string & text  )
{
	TiXmlElement* elem = this->getElementById(id);
	if( NULL == elem )
	{
		ttcode_log << "elem=" << elem << endl;
		return;
	}
	TiXmlElement* log = elem->FirstChildElement("logInfo");
	if( NULL == log )
	{
		log = new TiXmlElement("logInfo");
		elem->LinkEndChild(log);
	}
	else
	{
		log->Clear();
	}
	TiXmlElement* tag = elem->FirstChildElement(name);
	if( NULL == tag )
	{
		tag = new TiXmlElement(name);
		log->LinkEndChild(tag);
	}
	TiXmlText *pText = new TiXmlText(text);
	tag->LinkEndChild(pText);
	ttcode_log << "id=" << id << endl;
	ttcode_log << "name=" << name << endl;
	ttcode_log << "text=" << text << endl;
	m_ModifyFlag = true;
}




TiXmlElement* ProjectDocMgr::getFileByPath( const string & path )
{
	TiXmlElement* ret = searchFileByPath(m_Root,path);
	return ret;
}

TiXmlElement* ProjectDocMgr::searchFileByPath(TiXmlElement* root,const string & path)
{
	if( NULL == root )
	{
		return NULL;
	}
//	ttcode_log << "root=" << root << endl;
	const char *value = root->Attribute("path");
	if( value && path == string(value) )
	{
		return root;
	}
	TiXmlElement* item = root->FirstChildElement();
	for( ; item ; item = item->NextSiblingElement() )
	{
		TiXmlElement* ret = searchFileByPath(item,path);
		if( ret )
		{
			return ret;
		}
	}
	return NULL;
}
